package connection

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
	"log"
	"src/config"
	"sync"
	"time"
)

// DbRedis Redis 服务
type DbRedis struct {
	Client *redis.Pool
	Closed bool
	sync.Mutex
}

func (this *DbRedis) NewDbRedis() *DbRedis {
	this = (&DbRedis{}).DbRedisInIt()
	if this == nil {
		//1秒后重链
		time.Sleep(1 * time.Second)
		return this.DbRedisInIt()
	}
	return this
}

// DbRedis2  init
func GetDbRedisPool() *redis.Pool {

	//Addr:     viper.GetString("db.redis.conf.ip") + ":" + viper.GetString("db.redis.conf.port"),
	//	Password: viper.GetString("db.redis.conf.password"), // 如果没有设置密码，则为空字符串
	//		DB:       viper.GetInt("db.redis.conf.db"),          // 使用默认数据库

	address := config.V().GetString("db.redis.conf.ip") + ":" + config.V().GetString("db.redis.conf.port")
	password := config.V().GetString("db.redis.conf.password")
	db := config.V().GetInt("db.redis.conf.db")
	MaxIdle := config.V().GetInt("db.redis.conf.maxIdle")
	Active := config.V().GetInt("db.redis.conf.active")
	Auth := config.V().GetBool("db.redis.conf.auth")
	IdleTimeout := config.V().GetInt("db.redis.conf.idleTimeout")
	return &redis.Pool{
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
		MaxIdle:     MaxIdle, //最初的连接数量
		MaxActive:   Active,  //最大连接数 0自动 按需分配
		IdleTimeout: time.Duration(IdleTimeout) * time.Second,
		Wait:        true, //超过连接数后是否等待
		Dial: func() (redis.Conn, error) {
			redisUri := address
			if Auth {
				redisCon, err := redis.Dial("tcp", redisUri,
					redis.DialPassword(password), redis.DialDatabase(db))
				if err != nil {
					log.Println("redisConn2 链接失败", err)
				}
				return redisCon, nil
			} else {
				redisCon, err := redis.Dial("tcp", redisUri, redis.DialDatabase(db))
				if err != nil {
					log.Println("redisConn3 链接失败", err)
				}
				return redisCon, nil
			}
		},
	}
}

var DbRedisClient *DbRedis

func GetRedis() *DbRedis {
	if DbRedisClient == nil {
		pool := GetDbRedisPool()
		if pool == nil {
			log.Println("redis InIt 链接错误")
			//panic("redis 链接错误")
		}
		DbRedisClient = &DbRedis{Client: pool}
	}
	con_err := DbRedisClient.Ping()

	if con_err != nil {
		//pool := GetDbRedisPool()
		//if pool == nil {
		//	log.Println("redis InIt 链接错误")
		//	//panic("redis 链接错误")
		//}
		//dbRedis = &DbRedis{Client: pool}
		panic(con_err)
	}
	return DbRedisClient
}
func test2() {
	//GetRedis().Client.Get()
}

// ConnectRedis 连接 subscribe 数据库，设置全局的 Redis 对象
func (this *DbRedis) DbRedisInIt() *DbRedis {
	//var dbRedis *DbRedis
	once.Do(func() {

		pool := GetDbRedisPool()
		if pool == nil {
			log.Println("redis InIt 链接错误")
			//panic("redis 链接错误")
		}
		DbRedisClient = &DbRedis{Client: pool}

	})
	con_err := DbRedisClient.Ping()

	if con_err != nil {
		//pool := GetDbRedisPool()
		//if pool == nil {
		//	log.Println("redis InIt 链接错误")
		//	//panic("redis 链接错误")
		//}
		//dbRedis = &DbRedis{Client: pool}
		panic(con_err)
	}
	return DbRedisClient
}
func (rds *DbRedis) Close() {
	rds.Closed = true
	defer func(Client *redis.Pool) {
		err := Client.Close()
		if err != nil {

		}
	}(rds.Client)
	return
}

// Ping 用以测试 subscribe 连接是否正常
func (rds *DbRedis) Ping() error {
	_, err := rds.Client.Get().Do("ping")
	return err
}

// Set 存储 key 对应的 value，且设置 expiration 过期时间（单位纳秒）
func (rds *DbRedis) Setex(key string, expiration int, value interface{}) bool {
	conn := rds.Client.Get()
	defer rds.Close()
	if _, err := conn.Do("setex", key, expiration, value); err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

// Get 获取 key 对应的 value
func (rds *DbRedis) Get(key string) string {
	conn := rds.Client.Get()
	defer rds.Close()
	result, err := redis.String(conn.Do("Get", key))
	if err != nil {
		return ""
	}
	return result
}

// Get 获取 key 对应的 value
func (rds *DbRedis) Rpop(key string) (string, error) {
	conn := rds.Client.Get()
	defer rds.Close()
	result, err := redis.String(conn.Do("Rpop", key))
	if err != nil {
		return "", err
	}
	return result, nil
}
func (rds *DbRedis) SendPublish(channelName string, msg any) error {
	conn := rds.Client.Get()
	defer rds.Close()
	err := conn.Send("Publish", channelName, msg)
	if err != nil {
		return err
	}

	err = conn.Flush()
	if err != nil {
		return err
	}
	return nil
}
func (rds *DbRedis) DoPublish(channelName string, msg any) (any, error) {
	conn := rds.Client.Get()
	defer rds.Close()
	result, err := conn.Do("Publish", channelName, msg)
	if err != nil {
		return "", err
	}
	return result, nil
}
